package com.joelemon.mockinfluxdbdata.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;

/**
 * Json工具
 */
public class JsonUtil {

    private static ObjectMapper createMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(JsonParser.Feature.ALLOW_MISSING_VALUES, true);
        mapper.configure(JsonParser.Feature.IGNORE_UNDEFINED, true);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapper;
    }

    public static String convertJsonString(Object objValue) {
        return convertJsonString(objValue, true, true);
    }

    public static String convertJsonString(Object objValue, boolean isPretty, boolean ignoreNullValue) {
        ObjectMapper mapper = createMapper();
        if (ignoreNullValue) {
            mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        }
        String jsonStr = "{}";

        try {
            if (isPretty) {

                jsonStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(objValue);

            } else {
                jsonStr = mapper.writeValueAsString(objValue);
            }
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException(e.getMessage(), e);
        }

        return jsonStr;

    }

    public static <T> T convertObject(String jsonString, Class<T> valueType) {
        ObjectMapper mapper = createMapper();
        T result = null;
        try {
            result = mapper.readValue(jsonString, valueType);
        } catch (IOException e) {
            throw new IllegalArgumentException(e.getMessage(), e);
        }
        return result;
    }

    /**
     * 字符串转map复杂类型
     *
     * @param jsonString
     * @param valueType
     * @param <T>
     * @return
     */
    public static <T> Map<String, T> convertMap(String jsonString, TypeReference<Map<String, T>> valueType) {
        ObjectMapper mapper = createMapper();
        Map<String, T> result = null;
        try {
            result = mapper.readValue(jsonString, valueType);
        } catch (IOException e) {
            throw new IllegalArgumentException(e.getMessage(), e);
        }
        return result;
    }

    /**
     * Json字符串转对象
     *
     * @param jsonString   Json字符串
     * @param valueType    返回对象类型
     * @param subValueType 返回对象使用泛型类型
     * @param <T>          返回对象
     * @param <V>          使用泛型类型
     * @return
     * @throws IOException
     */
    public static <T, V> T convertObject(String jsonString, Class<T> valueType, Class<V> subValueType) {
        ObjectMapper mapper = createMapper();
        JavaType javaType = mapper.getTypeFactory().constructParametricType(valueType, subValueType);
        T result = null;
        try {
            result = mapper.readValue(jsonString, javaType);
        } catch (IOException e) {
            throw new IllegalArgumentException(e.getMessage(), e);
        }
        return result;
    }

    public static <T> T convertObjectFromMap(Map<String, Object> jsonMap, Class<T> valueType) {
        T result = convertObject(convertJsonString(jsonMap), valueType);

        return result;
    }

    public static <T> T convertObjectFromObject(Object jsonObject, Class<T> valueType) {
        T result = convertObject(convertJsonString(jsonObject), valueType);

        return result;
    }

    public <K, V> V getFirstOrNull(Map<K, V> map) {
        V obj = null;
        Iterator i$ = map.entrySet().iterator();

        while (i$.hasNext()) {
            Map.Entry<K, V> entry = (Map.Entry) i$.next();
            obj = entry.getValue();
            if (obj != null) {
                break;
            }
        }

        return obj;
    }

    static {
        EXCLUDE_EMPTY = new JsonUtil();
        EXCLUDE_DEFAULT = new JsonUtil();
        DEFAULT = new JsonUtil();
    }

    public static final JsonUtil EXCLUDE_EMPTY;
    public static final JsonUtil EXCLUDE_DEFAULT;
    public static final JsonUtil DEFAULT;
}
